module testbench();

reg         clock;
reg         reset;
integer     i, outfile, counter;


SingleCycle_CPU CPU(
    .clock  (clock),
    .reset  (reset)
);

always #5 clock = ~clock;    

  
initial begin
    // Initialize instruction memory to zero
    for(i=0; i<256; i=i+1) begin
        CPU.iMem.memory[i] = 32'b0;
    end
    
    // Initialize data memory to zero
    for(i=0; i<32; i=i+1) begin
        CPU.dMem.memory[i] = 8'b0;
    end    
        
    // initialize registers to zero
    for(i=0; i<32; i=i+1) begin
        CPU.registerFile.register[i] = 32'b0;
    end
    
    // Set Input n into data memory at 0x00
    for(i=0; i<32; i=i+1)begin
      CPU.dMem.memory[4*i[7:0]] = i;
    end
    // Load instructions into instruction memory
    $readmemh("instruction.txt", CPU.iMem.memory);
    
    // Open output file
    outfile = $fopen("output.txt") | 1;
    
    counter = 0;
    clock = 0;
    reset = 0;
    #10 reset = 1;
end
  
always@(posedge clock) begin
    // if(counter == 60)    // stop after 60 cycles
        // $stop;
    
    // print PC
    $fdisplay(outfile, "PC = %d", CPU.PC.PC_out);
    
    // print Registers
    $fdisplay(outfile, "Registers");
    $fdisplay(outfile, "R0(r0) =%d, R8 (t0) =%d, R16(s0) =%d, R24(t8) =%d", CPU.registerFile.register[0], CPU.registerFile.register[8] , CPU.registerFile.register[16], CPU.registerFile.register[24]);
    $fdisplay(outfile, "R1(at) =%d, R9 (t1) =%d, R17(s1) =%d, R25(t9) =%d", CPU.registerFile.register[1], CPU.registerFile.register[9] , CPU.registerFile.register[17], CPU.registerFile.register[25]);
    $fdisplay(outfile, "R2(v0) =%d, R10(t2) =%d, R18(s2) =%d, R26(k0) =%d", CPU.registerFile.register[2], CPU.registerFile.register[10], CPU.registerFile.register[18], CPU.registerFile.register[26]);
    $fdisplay(outfile, "R3(v1) =%d, R11(t3) =%d, R19(s3) =%d, R27(k1) =%d", CPU.registerFile.register[3], CPU.registerFile.register[11], CPU.registerFile.register[19], CPU.registerFile.register[27]);
    $fdisplay(outfile, "R4(a0) =%d, R12(t4) =%d, R20(s4) =%d, R28(gp) =%d", CPU.registerFile.register[4], CPU.registerFile.register[12], CPU.registerFile.register[20], CPU.registerFile.register[28]);
    $fdisplay(outfile, "R5(a1) =%d, R13(t5) =%d, R21(s5) =%d, R29(sp) =%d", CPU.registerFile.register[5], CPU.registerFile.register[13], CPU.registerFile.register[21], CPU.registerFile.register[29]);
    $fdisplay(outfile, "R6(a2) =%d, R14(t6) =%d, R22(s6) =%d, R30(s8) =%d", CPU.registerFile.register[6], CPU.registerFile.register[14], CPU.registerFile.register[22], CPU.registerFile.register[30]);
    $fdisplay(outfile, "R7(a3) =%d, R15(t7) =%d, R23(s7) =%d, R31(ra) =%d", CPU.registerFile.register[7], CPU.registerFile.register[15], CPU.registerFile.register[23], CPU.registerFile.register[31]);

    // print Data Memory
    $fdisplay(outfile, "Data Memory: 0x00 =%d", {CPU.dMem.memory[3] , CPU.dMem.memory[2] , CPU.dMem.memory[1] , CPU.dMem.memory[0] });
    $fdisplay(outfile, "Data Memory: 0x04 =%d", {CPU.dMem.memory[7] , CPU.dMem.memory[6] , CPU.dMem.memory[5] , CPU.dMem.memory[4] });
    $fdisplay(outfile, "Data Memory: 0x08 =%d", {CPU.dMem.memory[11], CPU.dMem.memory[10], CPU.dMem.memory[9] , CPU.dMem.memory[8] });
    $fdisplay(outfile, "Data Memory: 0x0c =%d", {CPU.dMem.memory[15], CPU.dMem.memory[14], CPU.dMem.memory[13], CPU.dMem.memory[12]});
    $fdisplay(outfile, "Data Memory: 0x10 =%d", {CPU.dMem.memory[19], CPU.dMem.memory[18], CPU.dMem.memory[17], CPU.dMem.memory[16]});
    $fdisplay(outfile, "Data Memory: 0x14 =%d", {CPU.dMem.memory[23], CPU.dMem.memory[22], CPU.dMem.memory[21], CPU.dMem.memory[20]});
    $fdisplay(outfile, "Data Memory: 0x18 =%d", {CPU.dMem.memory[27], CPU.dMem.memory[26], CPU.dMem.memory[25], CPU.dMem.memory[24]});
    $fdisplay(outfile, "Data Memory: 0x1c =%d", {CPU.dMem.memory[31], CPU.dMem.memory[30], CPU.dMem.memory[29], CPU.dMem.memory[28]});
	
    $fdisplay(outfile, "\n");
    
    counter = counter + 1;
end

endmodule